package utils

/**
 * @Description
 * @Author ggr
 * @Date 2021/7/8 21:06
 **/

import (
	"errors"
	"fmt"
	"github.com/Sir-yuChen/funAnalyse/global"
	"github.com/Sir-yuChen/funAnalyse/model"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"go.uber.org/zap"
	"math/rand"
	"net/url"
	"path"
	"strconv"
	"strings"
	"time"
)

var (
	defaultSheetName = "Sheet1" //默认Sheet名称
	defaultHeight    = 25.0     //默认行高度
)

type lkExcelExport struct {
	file      *excelize.File
	FileName  string
	SheetName string      //可定义默认sheet名称
	SheetMs   []SheetInfo //处理过后的sheet
}
type SheetInfo struct {
	SheetName  string //可定义默认sheet名称
	SheetIndex int
}

// ReadExcelInfo 读取excel文件数据
type ReadExcelInfo struct {
	ReadNumber int                        `json:"readNumber,omitempty"` //分批读取数据量 默认10000
	ExcelData  [][]map[string]interface{} `json:"excelData,omitempty"`  //读取到的数据
	ExcelFile  model.StockFilesModel      //上传的excel文件信息
}

func NewMyExcel() *lkExcelExport {
	return &lkExcelExport{file: nil, SheetName: "", FileName: "stock"}
}
func NewReadExcel() *ReadExcelInfo {
	return &ReadExcelInfo{}
}

// ReadFromExcel  读取文件
func (r *ReadExcelInfo) ReadFromExcel() (*ReadExcelInfo, error) {
	filePath := r.ExcelFile.FilePath
	if filePath == "" {
		global.GVA_LOG.Error("读取文件数据异常,文件路径不能为空")
		return nil, errors.New("读取文件数据异常,文件路径不能为空")
	}
	if exist, err := FileExist(filePath); err != nil || !exist {
		global.GVA_LOG.Error("读取文件数据异常,文件不存在")
		// 文件不存在 修改数据库状态
		if err := global.GVA_DB.Model(model.StockFilesModel{}).Where(" id = ?", r.ExcelFile.Id).Update("status", "D").Error; err != nil {
			global.GVA_LOG.Error("读取文件数据异常 文件不存在，修改文件状态异常", zap.Error(err))
		}
		return nil, errors.New("读取文件数据异常,文件不存在")
	}
	f, err := excelize.OpenFile(filePath)
	if err != nil {
		global.GVA_LOG.Error("读取文件数据异常", zap.Error(err), zap.Any("ReadExcelInfo", r))
		return nil, err
	}
	defer func() { _ = f.Close() }()
	//获取所有sheet名
	sheetList := f.GetSheetList()
	var count int
	headers := make([]string, 0)
	datas := make([][]map[string]interface{}, len(sheetList))
	for i, s := range sheetList {
		rows, _ := f.Rows(s)
		mapList := make([]map[string]interface{}, 0)
		for rows.Next() {
			row, _ := rows.Columns()
			if count == 0 { //表格的首行
				for _, colCell := range row {
					headers = append(headers, colCell)
				}
			} else {
				itemMap := map[string]interface{}{}
				for index, colCell := range row {
					if index > len(headers)-1 {
						break
					}
					itemMap[headers[index]] = colCell
				}
				mapList = append(mapList, itemMap)
			}
			count++
		}
		datas[i] = mapList
	}
	r.ExcelData = datas
	return r, nil
}

// ExportToPath 导出基本的表格
func (l *lkExcelExport) ExportToPath(params []map[string]string, data [][]map[string]interface{}, pathUrl string) (string, error) {
	l.handerSheet()
	l.export(params, data)
	completeFileName := l.createExcelFileName()
	filePath := ""
	if pathUrl != "" {
		filePath = pathUrl + "/" + completeFileName
	} else {
		filePath = path.Join(GetAbsPath(), global.GVA_CONFIG.File.UploadConfLocal.LocalDirectory, completeFileName)
	}
	err := l.file.SaveAs(filePath)
	return filePath, err
}

// ExportToWeb 导出到浏览器。此处使用的gin框架 其他框架可自行修改ctx
func (l *lkExcelExport) ExportToWeb(params []map[string]string, data [][]map[string]interface{}, ctx *gin.Context) {
	l.handerSheet()
	l.export(params, data)
	//删除默认的工作页Sheet1
	l.file.DeleteSheet("Sheet1")
	buffer, _ := l.file.WriteToBuffer()
	//设置文件类型
	ctx.Header("Content-Type", "application/vnd.ms-excel;charset=utf8")
	//设置文件名称
	ctx.Header("Content-Disposition", "attachment; filename="+url.QueryEscape(l.createExcelFileName()))
	_, _ = ctx.Writer.Write(buffer.Bytes())
}

//设置首行
func (l *lkExcelExport) writeTop(params []map[string]string) {
	topStyle, _ := l.file.NewStyle(`{"font":{"bold":true},"alignment":{"horizontal":"center","vertical":"center"}}`)
	for _, sheet := range l.SheetMs {
		l.file.SetActiveSheet(sheet.SheetIndex)
		var word = 'A'
		//首行写入
		for _, conf := range params {
			title := conf["title"]
			comment := conf["comment"]
			width, _ := strconv.ParseFloat(conf["width"], 64)
			line := fmt.Sprintf("%c1", word)
			//设置标题
			_ = l.file.SetCellValue(sheet.SheetName, line, title)
			//列宽
			_ = l.file.SetColWidth(sheet.SheetName, fmt.Sprintf("%c", word), fmt.Sprintf("%c", word), width)
			//设置样式
			_ = l.file.SetCellStyle(sheet.SheetName, line, line, topStyle)
			if comment != "" {
				//添加备注 err := f.AddComment("Sheet1", "A30", `{"author":"备注: ","text":"This is a comment."}`)
				_ = l.file.AddComment(sheet.SheetName, line, `{"author":"字段中文备注: ","text":"`+comment+`"}`)
			}
			word++
		}
	}
}

//写入数据
func (l *lkExcelExport) writeData(params []map[string]string, data [][]map[string]interface{}) {
	lineStyle, _ := l.file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"}}`)
	for h, sheet := range l.SheetMs {
		l.file.SetActiveSheet(sheet.SheetIndex)
		//数据写入
		var j = 2 //数据开始行数
		for i, val := range data[h] {
			//设置行高
			_ = l.file.SetRowHeight(sheet.SheetName, i+1, defaultHeight)
			//逐列写入
			var word = 'A'
			for _, conf := range params {
				valKey := conf["key"]
				line := fmt.Sprintf("%c%v", word, j)
				isNum := conf["is_num"]

				//设置值
				if isNum != "0" {
					valNum := fmt.Sprintf("'%v", val[valKey])
					_ = l.file.SetCellValue(sheet.SheetName, line, valNum)
				} else {
					_ = l.file.SetCellValue(sheet.SheetName, line, val[valKey])
				}
				//设置样式
				_ = l.file.SetCellStyle(sheet.SheetName, line, line, lineStyle)
				word++
			}
			j++
		}
		//设置行高 尾行
		_ = l.file.SetRowHeight(sheet.SheetName, len(data)+1, defaultHeight)
	}
}

func (l *lkExcelExport) export(params []map[string]string, data [][]map[string]interface{}) {
	l.writeTop(params)
	l.writeData(params, data)
}
func (l *lkExcelExport) handerSheet() {
	l.file = excelize.NewFile()
	var sheetMs []SheetInfo
	//处理工作页
	if l.SheetName != "" {
		sheets := strings.Split(l.SheetName, ",")
		for _, sheet := range sheets {
			index := l.file.NewSheet(sheet)
			sheetMs = append(sheetMs, SheetInfo{
				SheetName:  sheet,
				SheetIndex: index,
			})
		}
	} else {
		// 创建一个默认工作表
		index := l.file.NewSheet(defaultSheetName)
		sheetMs = append(sheetMs, SheetInfo{
			SheetName:  defaultSheetName,
			SheetIndex: index,
		})
	}
	l.SheetMs = sheetMs
}

func (l *lkExcelExport) createExcelFileName() string {
	t := time.Now().Format("2006-01-02-15-04-05")
	rand.Seed(time.Now().UnixNano())
	return fmt.Sprintf("excle-%v-%v-%v.xlsx", l.FileName, t, rand.Int63n(time.Now().Unix()))
}
